package name.flurl.android.tt_news4android;

import java.util.Hashtable;
import java.util.Timer;
import java.util.TimerTask;

import name.flurl.android.tt_news4android.Tt_news4AndroidApplication.CONSTANTS;
import android.app.Activity;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.Animation.AnimationListener;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.ViewFlipper;
import android.widget.CompoundButton.OnCheckedChangeListener;

public class GalleryActivity extends Activity {

	private boolean mSlideshowRunning = false;
	private Handler mSlideHandler = new Handler();
	private Handler mNextPreviousHandler = null;
	private Hashtable<String, Boolean> mLoadedImages = new Hashtable<String, Boolean>();
	private WaitForImageLoadRunnable mWaitForImageLoadRunnable = null;

	private ProgressDialog mProgressDialog = null;

	private NewsEntry mNews;
	// private SlideShow mSs;
	private ViewFlipper mFlipper;
	private View mNavigationView;
	private Animation mSlideLeftIn;
	private Animation mSlideLeftOut;
	private Animation mSlideRightIn;
	private Animation mSlideRightOut;

	private LazyImageView[] mImageSlots = new LazyImageView[4];
	private int mCurrentlyDisplayedImage = 0;

	private GestureDetector mGestureDetector;
	private OnTouchListener mGestureListener;
	private OnClickListener mClickListener;
	private boolean mFlingDetected = false;

	/** State of the activity */
	class State {
		public int currentImage = 0;
		public boolean slideshowRunning = false;
	}

	class ImageLoadedCallback implements Runnable {

		private String mUrl = null;

		public ImageLoadedCallback(String url) {
			super();
			mUrl = url;
		}

		@Override
		public void run() {
			GalleryActivity.this.onImageLoaded(mUrl);
		}
	};

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle icicle) {
		super.onCreate(icicle);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
				WindowManager.LayoutParams.FLAG_FULLSCREEN);
		setContentView(R.layout.gallery);

		final SharedPreferences sp = PreferenceManager
				.getDefaultSharedPreferences(this);

		if (sp.getBoolean("showTrafficWarningDlgPref", true)) {

			final Dialog dialog = new Dialog(this);
			dialog.setTitle(R.string.information);

			LinearLayout layout = new LinearLayout(this);
			layout.setOrientation(LinearLayout.VERTICAL);

			TextView msg = new TextView(this);
			msg.setText(R.string.traffic_warning_msg);
			layout.addView(msg);

			CheckBox chk = new CheckBox(this);
			chk.setText(R.string.dont_show_again);
			chk.setChecked(!sp.getBoolean("showTrafficWarningDlgPref", true));
			chk.setOnCheckedChangeListener(new OnCheckedChangeListener() {
				@Override
				public void onCheckedChanged(CompoundButton buttonView,
						boolean isChecked) {
					sp.edit().putBoolean("showTrafficWarningDlgPref",
							!isChecked).commit();
				}
			});
			layout.addView(chk);

			Button btn = new Button(this);
			btn.setText(R.string.ok);
			btn.setOnClickListener(new OnClickListener() {
				@Override
				public void onClick(View v) {
					dialog.dismiss();
				}
			});
			layout.addView(btn);

			dialog.setContentView(layout);
			dialog.show();
		}

		Bundle extras = getIntent().getExtras();
		mNews = (NewsEntry) extras.getSerializable("news");

		if (mNews.getImagesArray().length <= 4)
			mImageSlots = new LazyImageView[mNews.getImagesArray().length];

		mNextPreviousHandler = null;

		Runnable swipeLeft = new Runnable() {
			@Override
			public void run() {
				mFlingDetected = true;
				Timer timer = new Timer();
				timer.schedule(new TimerTask() {
					@Override
					public void run() {
						mFlingDetected = false;
					}
				}, 100);
				showNext();
			}
		};

		Runnable swipeRight = new Runnable() {
			@Override
			public void run() {
				mFlingDetected = true;
				Timer timer = new Timer();
				timer.schedule(new TimerTask() {
					@Override
					public void run() {
						mFlingDetected = false;
					}
				}, 100);
				showPrevious();
			}
		};

		mGestureDetector = new GestureDetector(
				new Tt_news4AndroidGestureDetector(swipeLeft, swipeRight, null,
						null));
		mGestureListener = new View.OnTouchListener() {
			public boolean onTouch(View v, MotionEvent event) {
				// Log.i("POGA gesture listener", "gestureListener");
				if (mGestureDetector.onTouchEvent(event)) {
					return true;
				}
				return false;
			}
		};
		mClickListener = new View.OnClickListener() {
			public void onClick(View v) {
				if (!mFlingDetected) {
					// Log.i("POGA click listener", "CLICK");

					toggleNavigation();
				}
			}
		};

		mSlideLeftIn = AnimationUtils.loadAnimation(this, R.anim.slide_left_in);
		mSlideLeftOut = AnimationUtils.loadAnimation(this,
				R.anim.slide_left_out);
		mSlideRightIn = AnimationUtils.loadAnimation(this,
				R.anim.slide_right_in);
		mSlideRightOut = AnimationUtils.loadAnimation(this,
				R.anim.slide_right_out);

		initLayout();
	}

	public void initLayout() {
		Integer currentView = 0;

		mFlipper = (ViewFlipper) findViewById(R.id.GalleryViewFlipper);
		mNavigationView = findViewById(R.id.GalleryNavigation);
		final State state = (State) getLastNonConfigurationInstance();

		ImageView prevBtn = (ImageView) findViewById(R.id.PreviousButton);
		ImageView nextBtn = (ImageView) findViewById(R.id.NextButton);
		ImageView playPauseBtn = (ImageView) findViewById(R.id.PlayPauseButton);

		prevBtn.setOnClickListener(new View.OnClickListener() {
			public void onClick(View v) {
				showPrevious();
			}
		});
		nextBtn.setOnClickListener(new View.OnClickListener() {
			public void onClick(View v) {
				showNext();
			}
		});

		playPauseBtn.setOnClickListener(new View.OnClickListener() {
			public void onClick(View v) {
				// Log.i("POGA events", "play onclick");
				toggleSlideshow();
			}
		});

		TextView eventTitleView = (TextView) findViewById(R.id.EventTitle);
		eventTitleView.setText(mNews.getmTitle());

		if (state != null) {
			mCurrentlyDisplayedImage = state.currentImage;
			mSlideshowRunning = state.slideshowRunning;
		}

		final String[] urls = mNews.getImagesArray();
		for (int i = 0; i < mImageSlots.length; i++) {
			int j = i + mCurrentlyDisplayedImage;
			// Log.i("POGA Events initLayout", "i:" + i + "j:" + j +
			// "urls.length:" + urls.length);
			if (j >= urls.length)
				j = j - urls.length;
			// load the previous image in the first imageview
			// String url = (j == 0) ? urls[urls.length - 1] : urls[j - 1];
			String url = urls[j];
			mImageSlots[i] = new LazyImageView(this, url,
					new ImageLoadedCallback(url));
			mImageSlots[i].setOnClickListener(mClickListener);
			mImageSlots[i].setOnTouchListener(mGestureListener);
			mFlipper.addView(mImageSlots[i]);
		}

		mImageSlots[0].setmOnLoadCallback(new Runnable() {
			private String mUrl = urls[mCurrentlyDisplayedImage];

			@Override
			public void run() {
				onImageLoaded(mUrl);
				preloadImages(CONSTANTS.DIRECTION_NEXT);
				preloadImages(CONSTANTS.DIRECTION_PREVIOUS);
				dismissLoadingDlg();
				// Log.i("POGA bp1", "BP1");
				if (mSlideshowRunning) {
					// Log.i("POGA bp2", "BP2");
					// set member back, so that toggle slideshow sets it right
					mSlideshowRunning = false;
					toggleSlideshow();
				}
			}
		});

		showLoadingDlg();
		mFlipper.setDisplayedChild(currentView);
		mImageSlots[0].load();
		updateImageCount();
	}

	private void updateImageCount() {
		((TextView) findViewById(R.id.ImageCount)).setText(String.format(
				"%s/%s", mCurrentlyDisplayedImage + 1,
				mNews.getImagesArray().length));
	}

	private void preloadImages(Integer direction) {
		int current, imgViewToUse, imageToLoad;
		current = mFlipper.getDisplayedChild();

		if (direction == CONSTANTS.DIRECTION_NEXT) {
			if (current == mFlipper.getChildCount() - 1)
				imgViewToUse = 0;
			else
				imgViewToUse = current + 1;

			imageToLoad = mCurrentlyDisplayedImage + 1;
			if (imageToLoad == mNews.getImagesArray().length)
				imageToLoad = 0;
		} else {
			if (current == 0)
				imgViewToUse = mFlipper.getChildCount() - 1;
			else
				imgViewToUse = current - 1;

			imageToLoad = mCurrentlyDisplayedImage - 1;
			if (imageToLoad == -1)
				imageToLoad = mNews.getImagesArray().length - 1;
		}

		imageToLoad = getImageToDisplay(direction);

		// Log.i("POGA preload", "preloading images view:" + imgViewToUse +
		// "image:" + imageToLoad); // + " and " + previous);
		LazyImageView view = (LazyImageView) mFlipper.getChildAt(imgViewToUse);
		// if (!view.ismAlreadyLoaded()) {
		// view.loadPlaceholderImage();
		// try {
		// Thread.sleep(100);
		// } catch (InterruptedException e) {
		// e.printStackTrace();
		// }
		view.setmOnLoadCallback(new ImageLoadedCallback(
				mNews.getImagesArray()[imageToLoad]));
		view.load(mNews.getImagesArray()[imageToLoad]);
		// }
	}

	abstract class WaitForImageLoadRunnable implements Runnable {
		private String mUrl = null;

		public WaitForImageLoadRunnable() {
			super();
		}

		public WaitForImageLoadRunnable(String url) {
			super();
			setmUrl(url);
		}

		@Override
		public void run() {
			// Log.i("POGA WaitForImageLoadRunnable", getmUrl() + " -- " +
			// mLoadedImages.containsKey(getmUrl()));
			if (!mLoadedImages.containsKey(getmUrl())) {
				// Log.i("POGA WaitImageLoadRunnable", "in if");

				if (mNextPreviousHandler != null) {
					showLoadingDlg();
					mNextPreviousHandler.postDelayed(this, 500);
				}
			} else {
				if (mNextPreviousHandler != null) {
					mNextPreviousHandler.removeCallbacks(this);
					dismissLoadingDlg();
				}

				if (!mSlideshowRunning) {
					displayImage(getDirection());
				}
				mNextPreviousHandler = null;
			}
		}

		protected abstract int getDirection();

		public String getmUrl() {
			return mUrl;
		}

		public void setmUrl(String url) {
			mUrl = url;
		}
	};

	class WaitForPreviousImageLoadRunnable extends WaitForImageLoadRunnable {
		private int mDirection = CONSTANTS.DIRECTION_PREVIOUS;

		@Override
		protected int getDirection() {
			return mDirection;
		}

	}

	class WaitForNextImageLoadRunnable extends WaitForImageLoadRunnable {
		private int mDirection = CONSTANTS.DIRECTION_NEXT;

		@Override
		protected int getDirection() {
			return mDirection;
		}
	};

	public void showPrevious() {
		int next;
		next = getImageToDisplay(CONSTANTS.DIRECTION_PREVIOUS);
		// LazyImageView nextView = (LazyImageView) mFlipper.getChildAt(next);

		// Log.i("POGA Events", "next image: " + mEvent.getImagesArray()[next] +
		// " *** already loaded: " + mLoadedImages.toString());
		if (!mLoadedImages.containsKey(mNews.getImagesArray()[next])) {
			waitForImageLoad(next, CONSTANTS.DIRECTION_PREVIOUS);
		} else {
			// Log.i("POGA Events", "image already loaded");
			displayImage(CONSTANTS.DIRECTION_PREVIOUS);
		}
	}

	private void displayImage(int dir) {
		if (dir == CONSTANTS.DIRECTION_NEXT) {
			mFlipper.setInAnimation(mSlideLeftIn);
			mFlipper.setOutAnimation(mSlideLeftOut);
			mFlipper.showNext();
		} else {
			mFlipper.setInAnimation(mSlideRightIn);
			mFlipper.setOutAnimation(mSlideRightOut);
			mFlipper.showPrevious();
		}
		mCurrentlyDisplayedImage = getImageToDisplay(dir);
		preloadImages(dir);
		updateImageCount();
	}

	public void showNext() {
		int next;
		next = getImageToDisplay(CONSTANTS.DIRECTION_NEXT);
		// LazyImageView nextView = (LazyImageView) mFlipper.getChildAt(next);

		// Log.i("POGA Events", "next image: " + mEvent.getImagesArray()[next] +
		// " *** already loaded: " + mLoadedImages.toString());
		if (!mLoadedImages.containsKey(mNews.getImagesArray()[next])) {
			waitForImageLoad(next, CONSTANTS.DIRECTION_NEXT);
		} else {
			// Log.i("POGA Events", "image already loaded");
			displayImage(CONSTANTS.DIRECTION_NEXT);
		}
	}

	private void waitForImageLoad(int next, int dir) {
		// preloadImages(dir);
		// Log.i("POGA Events", "image not loaded");
		// if (mNextPreviousHandler == null) mNextPreviousHandler = new
		// Handler();
		if (mNextPreviousHandler == null)
			mNextPreviousHandler = new Handler();
		if (mWaitForImageLoadRunnable != null) {
			mNextPreviousHandler.removeCallbacks(mWaitForImageLoadRunnable);
		}
		if (dir == CONSTANTS.DIRECTION_NEXT) {
			mWaitForImageLoadRunnable = new WaitForNextImageLoadRunnable();
		} else {
			mWaitForImageLoadRunnable = new WaitForPreviousImageLoadRunnable();
		}
		mWaitForImageLoadRunnable.setmUrl(mNews.getImagesArray()[next]);

		mNextPreviousHandler.removeCallbacks(mWaitForImageLoadRunnable);
		mNextPreviousHandler.postDelayed(mWaitForImageLoadRunnable, 100);
	}

	private int getImageToDisplay(int dir) {
		int next;
		if (dir == CONSTANTS.DIRECTION_NEXT) {
			if (mCurrentlyDisplayedImage == mNews.getImagesArray().length - 1)
				next = 0;
			else
				next = mCurrentlyDisplayedImage + 1;
		} else {
			if (mCurrentlyDisplayedImage == 0)
				next = mNews.getImagesArray().length - 1;
			else
				next = mCurrentlyDisplayedImage - 1;
		}
		return next;
	}

	@Override
	public Object onRetainNonConfigurationInstance() {
		// Log.i("POGA GalleryActivity", "onRetainNonConfigurationInstance");
		if (mNextPreviousHandler != null && mWaitForImageLoadRunnable != null) {
			mNextPreviousHandler.removeCallbacks(mWaitForImageLoadRunnable);
		}
		State state = new State();
		state.currentImage = mCurrentlyDisplayedImage;
		state.slideshowRunning = mSlideshowRunning;

		disableSlideShow();

		return state;
	}

	@Override
	public void onDestroy() {
		super.onDestroy();
		// Log.i("POGA GalleryActivity", "onDestroy");
		disableSlideShow();
	}

	public void toggleNavigation() {
		if (mNavigationView.getVisibility() == View.VISIBLE) {
			hideNavigation();
		} else {
			showNavigation();
		}
	}

	public void showNavigation() {
		// Log.i("POGA events", "nav unhiding");
		Animation ani = AnimationUtils.loadAnimation(GalleryActivity.this,
				R.anim.slide_bottom_in);
		ani.setAnimationListener(new AnimationListener() {
			@Override
			public void onAnimationEnd(Animation animation) {
			}

			@Override
			public void onAnimationRepeat(Animation animation) {
			}

			@Override
			public void onAnimationStart(Animation animation) {
				mNavigationView.setVisibility(View.VISIBLE);
			}
		});
		mNavigationView.startAnimation(ani);
	}

	public void hideNavigation() {
		// Log.i("POGA events", "nav hiding");
		Animation ani = AnimationUtils.loadAnimation(GalleryActivity.this,
				R.anim.slide_bottom_out);
		ani.setAnimationListener(new AnimationListener() {
			@Override
			public void onAnimationEnd(Animation animation) {
				mNavigationView.setVisibility(View.GONE);
			}

			@Override
			public void onAnimationRepeat(Animation animation) {
			}

			@Override
			public void onAnimationStart(Animation animation) {
			}
		});
		mNavigationView.startAnimation(ani);
	}

	private Runnable mScheduleSlideTask = new Runnable() {
		@Override
		public void run() {
			// if the progress dialog is shown, just wait
			if (mProgressDialog != null) {
				mSlideHandler.removeCallbacks(this);
				mSlideHandler.postDelayed(this, 500);
			} else {
				SharedPreferences sp = PreferenceManager
						.getDefaultSharedPreferences(GalleryActivity.this);
				showNext();
				if (mSlideshowRunning)
					mSlideHandler.postDelayed(this, sp.getInt(
							"slideshowDelayPref", 4) * 1000);
				else
					mSlideHandler.removeCallbacks(this);
			}
		}
	};

	public void toggleSlideshow() {
		if (!mSlideshowRunning) {
			enableSlideShow();
		} else {
			disableSlideShow();
		}
	}

	private void enableSlideShow() {
		ImageView playPauseBtn = (ImageView) findViewById(R.id.PlayPauseButton);
		mSlideshowRunning = true;
		mSlideHandler.removeCallbacks(mScheduleSlideTask);
		mSlideHandler.postDelayed(mScheduleSlideTask, 100);
		playPauseBtn.setImageResource(R.drawable.pause);
	}

	private void disableSlideShow() {
		ImageView playPauseBtn = (ImageView) findViewById(R.id.PlayPauseButton);
		mSlideshowRunning = false;
		mSlideHandler.removeCallbacks(mScheduleSlideTask);
		playPauseBtn.setImageResource(R.drawable.play);
	}

	public void onImageLoaded(String url) {
		Log.i("POGA onImageLoad", url);
		mLoadedImages.put(url, true);
	}

	private void showLoadingDlg() {
		if (mProgressDialog == null) {
			mProgressDialog = new ProgressDialog(this);
			mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
			mProgressDialog.setMessage("Loading...");
			mProgressDialog.setCancelable(false);
			mProgressDialog.show();
		}

	}

	private void dismissLoadingDlg() {
		if (mProgressDialog != null) {
			mProgressDialog.dismiss();
			mProgressDialog = null;
		}
	}

}